package ctwing

import (
	"context"
	"encoding/json"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/sagoo-cloud/sagooiot/internal/consts"
	"github.com/sagoo-cloud/sagooiot/internal/model"
	"github.com/sagoo-cloud/sagooiot/internal/service"
	"github.com/sagoo-cloud/sagooiot/internal/task/sim/common"
)

type ctwing struct{}

var ctx context.Context = context.Background()

var ctwingIns *ctwing

var simMap sync.Map

var yesterdayCount byte
var yesLock sync.Mutex

var dayCount byte
var dayLock sync.Mutex

var monthCount byte
var monthLock sync.Mutex

var tryTotal byte = 10

func NewCtwing() *ctwing {
	if ctwingIns == nil {
		ctwingIns = &ctwing{}
		return ctwingIns
	}
	return ctwingIns
}

// SimList 查询账户的所有的sim卡信息，每天1点执行一次
func (c *ctwing) SimList(ctx context.Context, appKey, appSecret, body, subUrl string, pageIndex int) {
	params := "pageIndex=" + strconv.Itoa(pageIndex)
	g.Log().Info(ctx, params)
	res, err := HttpPost(appKey, appSecret, params, body, Ctwing_Sim_List)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}

	var data RespSimList
	err = json.Unmarshal([]byte(res), &data)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}

	if data.ResultCode != "0" {
		g.Log().Error(ctx, res)
		g.Log().Error(ctx, "pageIndex = ", pageIndex)
		if v, ok := simMap.Load(pageIndex); !ok {
			simMap.Store(pageIndex, byte(1))
			common.Pool.Add(ctx, func(ctx context.Context) {
				c.SimList(ctx, appKey, appSecret, body, subUrl, pageIndex)
			})
		} else {
			count := gconv.Byte(v)
			if count <= tryTotal {
				simMap.Store(pageIndex, count+1)
				common.Pool.Add(ctx, func(ctx context.Context) {
					c.SimList(ctx, appKey, appSecret, body, subUrl, pageIndex)
				})
			}
		}
	} else {
		// 如果返回的数据是空，表示没有sim卡了，不用继续请求了
		if len(data.Description.SimList) == 0 {
			simMap.Range(func(key, value any) bool {
				g.Log().Info(ctx, "pageIndex = ", key, " try ", value, " count ")
				simMap.Delete(key)
				return true
			})
			return
		}
		pageIndex++
		common.Pool.Add(ctx, func(ctx context.Context) {
			c.SimList(ctx, appKey, appSecret, body, subUrl, pageIndex)
		})
		common.Pool.Add(ctx, func(ctx context.Context) {
			c.updateCollect(ctx, &data)
		})
	}
}
func (c *ctwing) updateCollect(ctx context.Context, data *RespSimList) {
	for _, v := range data.Description.SimList {
		var in = model.SimCollectAddInput{}
		in.AccNumber = v.AccNumber
		in.ActivationTime = v.ActivationTime
		in.CreateTime = v.CreateTime
		in.CustId = v.CustId
		in.Iccid = v.Iccid
		in.Imsi = v.Imsi
		in.LastChangeDate = v.LastChangeDate
		in.SimStatus = strings.Join(v.SimStatus, ",")
		in.StatusCd = v.StatusCd
		in.StopTypeList = strings.Join(v.StopTypeList, ",")
		in.Types = consts.Ctwing
		in.SimTypes = "4"
		err := service.SimSimCollect().AddSimCollectByHttp(ctx, &in)
		if err != nil {
			g.Log().Error(ctx, err)
		}
	}
}

// QueryRealTraffic 查询当天、当月流量 ,每3小时查询一次
func (c *ctwing) QueryRealTraffic(ctx context.Context, appKey, appSecret, subUrl string, pageNum int) {
	g.Log().Info(ctx, "QueryRealTraffic.pageNum = ", pageNum)
	in := model.GetSimCollectListInput{}
	in.PageSize = 100
	in.PageNum = pageNum
	total, _, list, err := service.SimSimCollect().GetSimCollectList(ctx, &in)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	if len(list) == 0 {
		return
	}
	if pageNum+1 <= total {
		common.Pool.Add(ctx, func(ctx context.Context) {
			c.QueryRealTraffic(ctx, appKey, appSecret, subUrl, pageNum+1)
		})
	}
	common.Pool.Add(ctx, func(ctx context.Context) {
		c.batchQueryMonth(ctx, appKey, appSecret, list)
	})
	common.Pool.Add(ctx, func(ctx context.Context) {
		c.batchQueryDay(ctx, appKey, appSecret, list)
	})
}

// batchQueryDay 批量 日流量 查询
func (c *ctwing) batchQueryDay(ctx context.Context, appKey, appSecret string, list []*model.SimCollectOutput) {
	var accs []string
	for _, v := range list {
		accs = append(accs, v.AccNumber)
	}
	m := map[string]interface{}{
		"accessNumbers": accs,
		"custNumber":    list[0].CustId,
		"flowDate":      time.Now().Format("20060102"),
	}
	bs, _ := json.Marshal(m)
	resp, err := HttpPost(appKey, appSecret, "", string(bs), Ctwing_Batch_Flow_ByDay)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	var data BatchQueryDayRes
	err = json.Unmarshal([]byte(resp), &data)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	if data.Code != 0 {
		g.Log().Info(ctx, "查询日实时流量错误", resp)
		if dayCount < tryTotal {
			dayLock.Lock()
			dayCount++
			dayLock.Unlock()
			c.batchQueryYesterdayFlow(appKey, appSecret, list)
		} else {
			dayLock.Lock()
			dayCount = 0
			dayLock.Unlock()
		}
	}
	if data.Code == 0 && len(data.Data) > 0 {
		for _, v := range data.Data {
			var in model.SimRealTrafficAddInput
			in.AccessNumber = v.AccessNumber
			in.FlowAmount = v.FlowAmount
			in.RealDate = v.FlowDay
			in.Types = consts.Ctwing
			in.Unit = v.Unit
			in.MonthDay = consts.Day
			err := service.SimSimRealTraffic().AddSimRealTraffic(ctx, in)
			if err != nil {
				g.Log().Error(ctx, err)
				continue
			}
		}
	}
}

// batchQueryMonth 2.6.14 批量月度流量卡查询
func (c *ctwing) batchQueryMonth(ctx context.Context, appKey, appSecret string, list []*model.SimCollectOutput) {
	var accs []string
	for _, v := range list {
		accs = append(accs, v.AccNumber)
	}
	m := map[string]interface{}{
		"accessNumbers": accs,
		"custNumber":    list[0].CustId,
	}
	bs, _ := json.Marshal(m)
	r, err := HttpPost(appKey, appSecret, "", string(bs), Ctwing_Batch_Flow_ByMonth) // 2.6.14 批量月度流量卡查询
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	var data BatchQueryInsertRes
	err = json.Unmarshal([]byte(r), &data)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	if data.Code != 0 {
		g.Log().Info(ctx, "查询月实时流量错误", r)
		if monthCount < tryTotal {
			monthLock.Lock()
			monthCount++
			monthLock.Unlock()
			c.batchQueryYesterdayFlow(appKey, appSecret, list)
		} else {
			monthLock.Lock()
			monthCount = 0
			monthLock.Unlock()
		}
	}
	if data.Code == 0 && len(data.Data) > 0 {
		for _, v := range data.Data {
			var in model.SimRealTrafficAddInput
			in.AccessNumber = v.AccessNumber
			in.FlowAmount = v.FlowAmount
			in.RealDate = v.Month
			in.Types = consts.Ctwing
			in.Unit = v.Unit
			in.MonthDay = consts.Month
			err := service.SimSimRealTraffic().AddSimRealTraffic(ctx, in)
			if err != nil {
				g.Log().Error(ctx, err)
				continue
			}
		}

	}
}

// QueryHistoryTraffic 查询今天以前当月所有的流量，每天4点执行一次
func (c *ctwing) QueryHistoryTraffic(ctx context.Context, appKey, appSecret, subUrl string, pageNum int) {
	g.Log().Info(ctx, "QueryHistoryTraffic.pageNum = ", pageNum)
	in := model.GetSimCollectListInput{}
	in.PageSize = 100
	in.PageNum = pageNum
	total, _, list, err := service.SimSimCollect().GetSimCollectList(ctx, &in)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	if len(list) == 0 {
		return
	}
	if pageNum+1 <= total {
		common.Pool.Add(ctx, func(ctx context.Context) {
			c.QueryHistoryTraffic(ctx, appKey, appSecret, subUrl, pageNum+1)
		})
		common.Pool.Add(ctx, func(_ context.Context) {
			c.batchQueryYesterdayFlow(appKey, appSecret, list)
		})
	}

}
func (c *ctwing) batchQueryYesterdayFlow(appKey, appSecret string, list []*model.SimCollectOutput) {
	var accs []string
	for _, v := range list {
		accs = append(accs, v.AccNumber)
	}
	m := map[string]interface{}{
		"accessNumbers": accs,
		"custNumber":    list[0].CustId,
		"flowDate":      time.Now().AddDate(0, 0, -1).Format("20060102"),
	}
	bs, _ := json.Marshal(m)
	resp, err := HttpPost(appKey, appSecret, "", string(bs), Ctwing_Batch_YesterdayFlow)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	var data BatchQueryDayRes
	err = json.Unmarshal([]byte(resp), &data)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	if data.Code != 0 {
		g.Log().Info(ctx, "查询昨日流量错误", resp)
		if yesterdayCount < tryTotal {
			yesLock.Lock()
			yesterdayCount++
			yesLock.Unlock()
			c.batchQueryYesterdayFlow(appKey, appSecret, list)
		} else {
			yesLock.Lock()
			yesterdayCount = 0
			yesLock.Unlock()
		}
	}
	if data.Code == 0 && len(data.Data) > 0 {
		for _, v := range data.Data {
			var in model.SimHistoryTrafficAddInput
			in.AccessNumber = v.AccessNumber
			in.FlowAmount = v.FlowAmount
			in.FlowDay = v.FlowDay
			in.Types = consts.Ctwing
			in.Unit = v.Unit
			err := service.SimSimHistoryTraffic().AddSimHistoryTraffic(ctx, in)
			if err != nil {
				g.Log().Error(ctx, err)
				continue
			}
		}
	}

}
